package cn.org.tpeach.nosql.view;

import cn.org.tpeach.nosql.framework.LarkFrame;
import cn.org.tpeach.nosql.tools.DataStructureUtils;
import cn.org.tpeach.nosql.tools.StringUtils;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.fxml.FXMLLoader;
import javafx.fxml.JavaFXBuilderFactory;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Border;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.util.Duration;
import javafx.util.Pair;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * https://docs.oracle.com/javafx/2/api/javafx/stage/package-summary.html
 */
public class JavaFxUtil {
    /**
     * https://code.makery.ch/blog/javafx-dialogs-official/
     * @param window
     * @param title
     * @param header
     * @param contentText
     */
    public static void showMessageErrorDialog(Window window,  String title,String header,String contentText){
        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setTitle(title);
        alert.setHeaderText(header);
        if(StringUtils.length(contentText) > 300){
            Label label = new Label("The exception stacktrace was:");
            TextArea textArea = new TextArea(contentText);
            textArea.setEditable(false);
            textArea.setWrapText(true);
            textArea.setBorder(Border.EMPTY);
            textArea.setStyle("-fx-background-insets: 0");
            textArea.setMaxWidth(Double.MAX_VALUE);
            textArea.setMaxHeight(Double.MAX_VALUE);
            GridPane.setVgrow(textArea, Priority.ALWAYS);
            GridPane.setHgrow(textArea, Priority.ALWAYS);
            GridPane expContent = new GridPane();
            expContent.setMaxWidth(Double.MAX_VALUE);
            expContent.add(label, 0, 0);
            expContent.add(textArea, 0, 1);
            alert.getDialogPane().setExpandableContent(expContent);
            alert.setContentText(contentText.substring(0,300)+"...");
        }else{
            alert.setContentText(contentText);
        }
        alert.initOwner(window);
        alert.showAndWait();
    }
    public static void showMessageErrorDialog(Window window,  String header,String contentText){
        showMessageErrorDialog(window,"ERROR",header,contentText);
    }

    public static void showMessageInfoDialog(Window window,  String title,String header,String contentText){
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle(title);
        alert.setHeaderText(header);
        alert.setContentText(contentText);
        alert.initOwner(window);
        alert.showAndWait();
    }
    public static void showMessageInfoDialog(Window window,  String header,String contentText){
        showMessageInfoDialog(window,"INFORMATION",header,contentText);
    }
    public static boolean showConfirmDialogYNC(  String title, String contentText){
        return showConfirmDialogYNC(null,title,null,contentText);
    }
    public static boolean showConfirmDialogYNC(Window window,  String title,String header,String contentText){
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION,contentText,new ButtonType("取消", ButtonBar.ButtonData.NO),
                new ButtonType("确定", ButtonBar.ButtonData.YES));
        alert.setTitle(title);
        alert.setHeaderText(header);
        alert.initOwner(window);
        Optional<ButtonType> buttonType = alert.showAndWait();
        if(buttonType.get().getButtonData().equals(ButtonBar.ButtonData.YES)){
            return true;
        } else {
            return false;
        }
    }

    public static void setTipTime(Tooltip tooltip, int time){
        try {
            Class tipClass = tooltip.getClass();
            Field f = tipClass.getDeclaredField("BEHAVIOR");
            f.setAccessible(true);
            Class behavior = Class.forName("javafx.scene.control.Tooltip$TooltipBehavior");
            Constructor constructor = behavior.getDeclaredConstructor(Duration.class, Duration.class, Duration.class, boolean.class);
            constructor.setAccessible(true);
            f.set(behavior, constructor.newInstance(new Duration(300), new Duration(time), new Duration(300), false));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static ImageView createIcon(ImageView imageView, String path){
        if(imageView == null){
            imageView = new ImageView(path);
        }
        return imageView;
    }

    public static <R> Dialog<R> createDialog(Node node){
        Dialog<R> dialog = new Dialog<>();
        if(node != null){
            ObservableList<String> stylesheets = dialog.getDialogPane().getStylesheets();
            dialog.getDialogPane().getStylesheets().add("/view/css/default.css");
            dialog.getDialogPane().getStylesheets().add("/view/css/common.css");
            dialog.getDialogPane().setContent(node);
        }
        Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
        stage.getIcons().addAll(LarkFrame.primaryStage.getIcons());
        return dialog;
    }

    public static <T> T loadFxml(FXMLLoader fxmlLoader,String path) throws IOException {
        URL location = JavaFxUtil.class.getResource(path);
        fxmlLoader.setLocation(location);
        fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
        return fxmlLoader.load(location.openStream());
    }

    public static String tabString(String str){
        if(StringUtils.isBlank(str)){
            return "      ";
        }
        if(str.length() > 30){
            return str.substring(0,30)+"...";
        }else if(str.length() < 6){
            return "  "+str+"  ";
        }
        return str;
    }

    public static void setTooltipText(Control control,String text){
        if(control != null){
            Tooltip tooltip = control.getTooltip();
            if(tooltip == null){
                control.setTooltip(new Tooltip(text));
            }else{
                tooltip.setText(text);
            }

        }
    }

    public static void tabBindChangeListener(Tab tab, ChangeListener... listeners){
        if(DataStructureUtils.isNotEmpty(listeners)){
            List<ChangeListener> tabPaneChangeListener = (List<ChangeListener>) tab.getProperties().get("tabPaneChangeListener");
            if(tabPaneChangeListener == null){
                tabPaneChangeListener = new ArrayList<>();
                tab.getProperties().put("tabPaneChangeListener",tabPaneChangeListener);
            }
            for (ChangeListener listener : listeners) {
                tabPaneChangeListener.add(listener);
            }
        }
    }

    public static void closeTabRelease(TabPane tabPane,Tab tab){

        List<ChangeListener> tabPaneChangeListener = (List<ChangeListener>) tab.getProperties().get("tabPaneChangeListener");
        if(DataStructureUtils.isNotEmpty(tabPaneChangeListener)){
            for (ChangeListener changeListener : tabPaneChangeListener) {
                tabPane.widthProperty().removeListener(changeListener);
                tabPane.heightProperty().removeListener(changeListener);
            }
        }
        Object controller = tab.getProperties().get("controller");
        if(controller instanceof Closeable){
            try {
                ((Closeable) controller).close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        tab.getProperties().clear();
        tab.setUserData(null);
    }

    public static void exit(Event event){
        event.consume();
        boolean b = JavaFxUtil.showConfirmDialogYNC(LarkFrame.primaryStage, "确认", null, "确认退出");
        if(b){
            LarkFrame.primaryStage.close();
            System.exit(0);
        }
    }

    public static void showTest(){
        Dialog<Pair<String, String>> dialog = new Dialog<>();
        dialog.setTitle("Login Dialog");
        dialog.setHeaderText("Look, a Custom Login Dialog");

// Set the icon (must be included in the project).


// Set the button types.
        ButtonType loginButtonType = new ButtonType("Login", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL);

// Create the username and password labels and fields.
        GridPane grid = new GridPane();
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 150, 10, 10));

        TextField username = new TextField();
        username.setPromptText("Username");
        PasswordField password = new PasswordField();
        password.setPromptText("Password");

        grid.add(new Label("Username:"), 0, 0);
        grid.add(username, 1, 0);
        grid.add(new Label("Password:"), 0, 1);
        grid.add(password, 1, 1);

// Enable/Disable login button depending on whether a username was entered.
        Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType);
        loginButton.setDisable(true);

// Do some validation (using the Java 8 lambda syntax).
        username.textProperty().addListener((observable, oldValue, newValue) -> {
            loginButton.setDisable(newValue.trim().isEmpty());
        });

        dialog.getDialogPane().setContent(grid);

// Request focus on the username field by default.
        Platform.runLater(() -> username.requestFocus());

// Convert the result to a username-password-pair when the login button is clicked.
        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == loginButtonType) {
                return new Pair<>(username.getText(), password.getText());
            }
            return null;
        });
        dialog.show();

//        Optional<Pair<String, String>> result = dialog.showAndWait();
//
//        result.ifPresent(usernamePassword -> {
//            System.out.println("Username=" + usernamePassword.getKey() + ", Password=" + usernamePassword.getValue());
//        });
    }
}
